﻿
Imports std

Public Interface agent_t
    Function settings() As agent_settings
End Interface

Public MustInherit Class agent(Of T As agent_settings)
    Implements agent_t

    Private ReadOnly s As T = Nothing
    Private stopped As Boolean = False

    Protected Sub New(ByVal settings As T)
        Me.s = check_resolve_or_alloc(settings)
        start()
    End Sub

    Private Sub start()
        initial()
        If rotation_mode() Then
            assert_begin(New eventComb(Function() As Boolean
                                           Return waitfor(Function() precondition() OrElse stopped) AndAlso
                                                  goto_next()
                                       End Function,
                                       Function() As Boolean
                                           If stopped Then
                                               Return goto_end()
                                           Else
                                               Return waitfor(add(+cases())) AndAlso
                                                      goto_begin()
                                           End If
                                       End Function))
        End If
    End Sub

    Protected Overridable Function rotation_mode() As Boolean
        Return True
    End Function

    Protected Overridable Sub [stop]()
    End Sub

    Protected Overridable Sub initial()
    End Sub

    Protected Overridable Function precondition() As Boolean
        Return False
    End Function

    Protected Overridable Function cases() As vector(Of [case])
        assert(Not rotation_mode())
        Dim rtn As vector(Of [case]) = Nothing
        rtn = New vector(Of [case])()
        assert(rtn.push_back([case]()))
        Return rtn
    End Function

    Protected Overridable Function [case]() As [case]
        assert(False)
        Return Nothing
    End Function

    Public Function settings() As agent_settings Implements agent_t.settings
        Return typed_settings()
    End Function

    Public Function typed_settings() As T
        Return s
    End Function

    Private Sub debug_info(ByVal c As [case])
        assert(debug())
        assert(Not c Is Nothing)
        raiseError("add input case with category = ", c.category, ", action = ", c.action, ", mask = ", c.mask)
    End Sub

    Protected Function add(ByVal c As [case]) As eventComb
        If debug() Then
            Dim ec As eventComb = Nothing
            Return New eventComb(Function() As Boolean
                                     ec = input.add(c)
                                     Return waitfor(ec) AndAlso
                                            goto_next()
                                 End Function,
                                 Function() As Boolean
                                     If ec.end_result() Then
                                         debug_info(c)
                                         Return goto_end()
                                     Else
                                         Return False
                                     End If
                                 End Function)
        Else
            Return input.add(c)
        End If
    End Function

    Protected Function add(ByVal ParamArray cs() As [case]) As eventComb
        Dim i As Int64 = 0
        Dim ec As eventComb = Nothing
        Return New eventComb(Function() As Boolean
                                 If cs Is Nothing OrElse cs.Length() = 0 Then
                                     Return goto_end()
                                 Else
                                     Return goto_next()
                                 End If
                             End Function,
                             Function() As Boolean
                                 assert(i >= 0 AndAlso i < cs.Length())
                                 ec = add(cs(i))
                                 Return waitfor(ec) AndAlso
                                        goto_next()
                             End Function,
                             Function() As Boolean
                                 If ec.end_result() Then
                                     i += 1
                                     If i < cs.Length() Then
                                         Return goto_prev()
                                     Else
                                         Return goto_end()
                                     End If
                                 Else
                                     Return False
                                 End If
                             End Function)
    End Function

    Protected Overrides Sub Finalize()
        stopped = True
        [stop]()
        GC.KeepAlive(s)
        MyBase.Finalize()
    End Sub
End Class
